package com.hulk.dryad.web.filter;


import cn.hutool.http.HttpUtil;
import com.hulk.dryad.common.component.R;
import com.hulk.dryad.common.constant.enums.BEC;
import com.hulk.dryad.common.exception.BaseRteException;
import com.hulk.dryad.common.exception.SecurityRteException;
import com.hulk.dryad.common.util.RequestUtils;
import com.hulk.dryad.common.util.SignUtil;
import com.hulk.dryad.common.util.WebUtils;
import com.hulk.dryad.manage.provider.cache.SignKeyCache;
import com.hulk.dryad.manage.security.component.PermitAllSecurityUrlProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Ordered;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * @author hulk
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class SignatureFilter extends OncePerRequestFilter implements InitializingBean, Ordered {

	private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
	private final PermitAllSecurityUrlProperties permitAllSecurityUrlProperties;
	private final SignKeyCache signKeyCache;


	@SuppressWarnings("deprecation")
	@Override
	public void doFilterInternal(HttpServletRequest request, HttpServletResponse resp, FilterChain chain) throws IOException {
		try {
			log.debug("ContentType:[{}],HttpMethod:[{}]", request.getContentType(), request.getMethod());
			if (RequestUtils.isContainBody(request) && StringUtils.equalsAnyIgnoreCase(request.getContentType(),
					MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE)) {
				String path = request.getServletPath();
				boolean flag = !permitAllSecurityUrlProperties.getIgnoreUrls().stream().anyMatch(url -> PATH_MATCHER.match(url, path));
				if (flag) {
					chain.doFilter(new SignatureServletRequestWrapper(request, signKeyCache), resp);
				}else {
					chain.doFilter(request, resp);
				}
			} else if (RequestUtils.isGet(request) || RequestUtils.isDelete(request)) {
				String path = request.getServletPath();
				boolean urlFlag = !permitAllSecurityUrlProperties.getIgnoreUrls().stream().anyMatch(url -> PATH_MATCHER.match(url, path));
				Map param = HttpUtil.decodeParamMap(request.getServletPath(), StandardCharsets.UTF_8);
				if (param.containsKey(SignUtil.SIGNATURE) && urlFlag) {
					String signature = String.valueOf(param.get(SignUtil.SIGNATURE));
					boolean signFlag = SignUtil.verify(param, signature, signKeyCache.getSignKey());
					if (!signFlag) {
						throw new SecurityRteException(BEC.E_2005);
					}
				}
				chain.doFilter(request, resp);
			}

		} catch (BaseRteException e) {
			WebUtils.renderJson(resp, R.failed(e.getErrCode(), e.getErrDesc()));
		} catch (Exception e) {
			WebUtils.renderJson(resp, R.failed(BEC.E_9999));
		}
	}


	@Override
	public int getOrder() {
		return Ordered.LOWEST_PRECEDENCE - 1000;
	}
}
